package com.vegetable.common.aspect;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.vegetable.common.annotation.SalesCustomerPermission;
import com.vegetable.common.annotation.SalesDataPermission;
import com.vegetable.common.utils.HttpContextUtils;
import com.vegetable.modules.entity.baseData.AddressBook;
import com.vegetable.modules.entity.sys.SysUserEntity;
import com.vegetable.modules.entity.wx.SysUserDepartment;
import com.vegetable.modules.entity.wx.WxDepartment;
import com.vegetable.modules.service.baseData.IAddressBookService;
import com.vegetable.modules.service.wx.WxDepartmentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 销售数据权限切面类
 * 实现基于部门的销售数据权限控制功能
 *
 * 业务规则：
 * 1. 财务部门（部门ID为5）：可以看到全部的销售订单和销售出库单
 * 2. 销售部门（部门ID为3）：只能看到自己负责客户的销售订单和销售出库单
 * 3. 其他部门：无法看到销售订单和销售出库单
 * 4. 未关联部门的用户：无法看到销售订单和销售出库单
 *
 * 客户关联规则：
 * 1. address_book表中staff_type=1标识客商
 * 2. address_book表中salesman_id标识负责该客商的销售用户ID
 *
 * @author Qoder
 */
@Slf4j
@Aspect
@Component
public class DataPermissionAspect {
    
    @Autowired
    private WxDepartmentService wxDepartmentService;
    
    @Autowired
    private IAddressBookService addressBookService;
    
    @Pointcut("@annotation(com.vegetable.common.annotation.SalesCustomerPermission) || @annotation(com.vegetable.common.annotation.SalesDataPermission)")
    public void dataPermissionPointcut() {
    }
    
    @Around("dataPermissionPointcut()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        try {
            // 获取当前用户ID
            Long userId = getCurrentUserId();
            if (userId == null) {
                log.warn("无法获取当前用户ID，应用默认数据权限控制（不显示任何数据）");
                // 无法获取用户ID时，默认不显示任何数据，而不是跳过权限控制
                applyDefaultNoDataFilter(point);
                return point.proceed();
            }
            
            // 获取方法上的注解
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            SalesCustomerPermission salesCustomerPermission = method.getAnnotation(SalesCustomerPermission.class);
            SalesDataPermission salesDataPermission = method.getAnnotation(SalesDataPermission.class);
            
            if (salesCustomerPermission == null && salesDataPermission == null) {
                return point.proceed();
            }
            
            // 根据权限类型处理
            if (salesCustomerPermission != null) {
                switch (salesCustomerPermission.type()) {
                    case CUSTOMER:
                        handleCustomerPermission(point, salesCustomerPermission, userId);
                        break;
                    default:
                        log.warn("不支持的数据权限类型: {}", salesCustomerPermission.type());
                }
            } else if (salesDataPermission != null) {
                switch (salesDataPermission.type()) {
                    case CUSTOMER:
                        handleCustomerPermissionForPO(point, salesDataPermission, userId);
                        break;
                    default:
                        log.warn("不支持的数据权限类型: {}", salesDataPermission.type());
                }
            }
            
            return point.proceed();
        } catch (Exception e) {
            log.error("数据权限控制处理异常", e);
            // 发生异常时，默认不显示任何数据，确保安全性
            applyDefaultNoDataFilter(point);
            return point.proceed();
        }
    }
    
    /**
     * 处理客户数据权限
     */
    private void handleCustomerPermission(ProceedingJoinPoint point, SalesCustomerPermission salesCustomerPermission, Long userId) {
        try {
            // 获取用户所属部门
            List<WxDepartment> departments = wxDepartmentService.getSysUserDepartments(userId);
            if (CollectionUtils.isEmpty(departments)) {
                log.warn("用户{}未关联任何部门，无法进行数据权限控制", userId);
                // 用户未关联部门时，不显示任何数据
                filterNoDepartmentData(point, salesCustomerPermission);
                return;
            }
            
            // 检查用户是否属于财务部门（部门ID为5）
            boolean isFinanceDepartment = departments.stream()
                    .anyMatch(dept -> dept.getId() == 5);
            
            // 财务部门可以看到全部数据，无需过滤
            if (isFinanceDepartment) {
                log.debug("用户{}属于财务部门，可以查看全部客户数据", userId);
                return;
            }
            
            // 检查用户是否属于销售部门（部门ID为3）
            boolean isSalesDepartment = departments.stream()
                    .anyMatch(dept -> dept.getId() == 3);
            
            // 销售部门用户只能查看自己负责的客户数据
            if (isSalesDepartment) {
                List<Long> customerIds = getCustomerIdsBySalesmanId(userId);
                if (CollectionUtils.isEmpty(customerIds)) {
                    log.warn("销售用户{}未关联任何客户", userId);
                    // 如果销售没有关联客户，则不显示任何数据
                    customerIds = Arrays.asList(-1L); // 添加一个不存在的ID，确保查询结果为空
                }
                
                // 应用客户ID过滤
                applyCustomerFilter(point, salesCustomerPermission, customerIds);
                return;
            }
            
            // 其他部门用户看不到销售订单和销售出库单
            log.debug("用户{}属于其他部门，无法查看销售订单和销售出库单", userId);
            filterNoDepartmentData(point, salesCustomerPermission);
        } catch (Exception e) {
            log.error("处理客户数据权限异常", e);
        }
    }
    
    /**
     * 处理PO对象的客户数据权限
     */
    private void handleCustomerPermissionForPO(ProceedingJoinPoint point, SalesDataPermission salesDataPermission, Long userId) {
        try {
            // 获取用户所属部门
            List<WxDepartment> departments = wxDepartmentService.getSysUserDepartments(userId);
            if (CollectionUtils.isEmpty(departments)) {
                log.warn("用户{}未关联任何部门，无法进行数据权限控制", userId);
                // 用户未关联部门时，不显示任何数据
                filterNoDepartmentDataForPO(point, salesDataPermission, userId);
                return;
            }
            
            // 检查用户是否属于财务部门（部门ID为5）
            boolean isFinanceDepartment = departments.stream()
                    .anyMatch(dept -> dept.getId() == 5);
            
            // 财务部门可以看到全部数据，无需过滤
            if (isFinanceDepartment) {
                log.debug("用户{}属于财务部门，可以查看全部数据", userId);
                return;
            }
            
            // 检查用户是否属于销售部门（部门ID为3）
            boolean isSalesDepartment = departments.stream()
                    .anyMatch(dept -> dept.getId() == 3);
            
            // 销售部门用户只能查看自己负责的客户数据
            if (isSalesDepartment) {
                List<Long> customerIds = getCustomerIdsBySalesmanId(userId);
                if (CollectionUtils.isEmpty(customerIds)) {
                    log.warn("销售用户{}未关联任何客户", userId);
                    // 如果销售没有关联客户，则不显示任何数据
                    customerIds = Arrays.asList(-1L); // 添加一个不存在的ID，确保查询结果为空
                }
                
                // 应用客户ID过滤
                applyCustomerFilterForPO(point, salesDataPermission, customerIds);
                return;
            }
            
            // 其他部门用户看不到销售订单和销售出库单
            log.debug("用户{}属于其他部门，无法查看销售订单和销售出库单", userId);
            filterNoDepartmentDataForPO(point, salesDataPermission, userId);
        } catch (Exception e) {
            log.error("处理PO对象的客户数据权限异常", e);
        }
    }
    
    /**
     * 根据部门ID获取关联的客商ID列表
     */
    /*private List<Long> getCustomerIdsByDepartments(List<Long> departmentIds) {
        // TODO: 实际应该查询部门与客商的关联表
        // 这里暂时返回空列表，后续需要实现真实的关联查询
        return Arrays.asList();
    }*/
    
    /**
     * 应用客户ID过滤
     */
    private void applyCustomerFilter(ProceedingJoinPoint point, SalesCustomerPermission salesCustomerPermission, List<Long> customerIds) {
        try {
            // 获取方法参数
            Object[] args = point.getArgs();
            String filterParamName = salesCustomerPermission.filterParam();
            
            // 查找需要过滤的参数（Map或QueryWrapper类型）
            for (Object arg : args) {
                if (arg instanceof Map) {
                    // 处理Map参数
                    Map<String, Object> paramMap = (Map<String, Object>) arg;
                    if (filterParamName.equals("params") || paramMap.containsKey(filterParamName)) {
                        paramMap.put("customerIds", customerIds);
                    }
                } else if (arg instanceof QueryWrapper) {
                    // 处理QueryWrapper参数
                    QueryWrapper<?> queryWrapper = (QueryWrapper<?>) arg;
                    queryWrapper.in("customer_id", customerIds);
                }
            }
        } catch (Exception e) {
            log.error("应用客户ID过滤异常", e);
        }
    }
    
    /**
     * 应用PO对象的客户ID过滤
     */
    private void applyCustomerFilterForPO(ProceedingJoinPoint point, SalesDataPermission salesDataPermission, List<Long> customerIds) {
        try {
            // 获取方法参数
            Object[] args = point.getArgs();
            Class<?> filterParamClass = salesDataPermission.filterParam();
            
            // 查找需要过滤的PO参数
            for (Object arg : args) {
                if (arg != null && filterParamClass.isAssignableFrom(arg.getClass())) {
                    // 通过反射设置customerIds字段
                    try {
                        java.lang.reflect.Field customerIdsField = arg.getClass().getDeclaredField("customerIds");
                        customerIdsField.setAccessible(true);
                        customerIdsField.set(arg, customerIds);
                    } catch (NoSuchFieldException e) {
                        log.debug("PO对象{}中未找到customerIds字段", arg.getClass().getName());
                    }
                }
            }
        } catch (Exception e) {
            log.error("应用PO对象的客户ID过滤异常", e);
        }
    }
    
    /**
     * 过滤无部门用户的数据（不显示任何数据）
     */
    private void filterNoDepartmentData(ProceedingJoinPoint point, SalesCustomerPermission salesCustomerPermission) {
        try {
            // 添加一个不存在的客户ID，确保查询结果为空
            List<Long> emptyCustomerIds = Arrays.asList(-1L);
            applyCustomerFilter(point, salesCustomerPermission, emptyCustomerIds);
        } catch (Exception e) {
            log.error("过滤无部门用户数据异常", e);
        }
    }
    
    /**
     * 过滤无部门用户的数据（PO对象版本）
     */
    private void filterNoDepartmentDataForPO(ProceedingJoinPoint point, SalesDataPermission salesDataPermission, Long userId) {
        try {
            // 添加一个不存在的客户ID，确保查询结果为空
            List<Long> emptyCustomerIds = Arrays.asList(-1L);
            applyCustomerFilterForPO(point, salesDataPermission, emptyCustomerIds);
        } catch (Exception e) {
            log.error("过滤无部门用户数据异常", e);
        }
    }
    /**
     * 根据销售用户ID获取其负责的客户ID列表
     * 客户表address_book中staff_type=1标识客商，salesman_id标识负责该客户的销售用户ID
     */
    private List<Long> getCustomerIdsBySalesmanId(Long salesmanId) {
        try {
            QueryWrapper<AddressBook> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("staff_type", 1); // 客商类型
            queryWrapper.eq("salesman_id", salesmanId); // 负责的销售用户ID
            queryWrapper.eq("is_del", 0); // 未删除的记录
            
            List<AddressBook> customers = addressBookService.list(queryWrapper);
            return customers.stream()
                    .map(AddressBook::getId)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("根据销售用户ID获取客户ID列表异常", e);
            return Arrays.asList();
        }
    }
    
    /**
     * 获取当前用户ID
     */
    private Long getCurrentUserId() {
        try {
            // 从Shiro安全框架中获取当前用户ID
            Subject subject = SecurityUtils.getSubject();
            if (subject != null) {
                Object principal = subject.getPrincipal();
                if (principal instanceof SysUserEntity) {
                    SysUserEntity user = (SysUserEntity) principal;
                    return user.getUserId();
                }
            }
            
            // 从请求上下文中获取用户信息（备用方案）
            Object userIdObj = HttpContextUtils.getHttpServletRequest().getAttribute("userId");
            if (userIdObj != null) {
                return Long.valueOf(userIdObj.toString());
            }
        } catch (Exception e) {
            log.error("获取当前用户ID异常", e);
        }
        return null;
    }
    
    /**
     * 应用默认的无数据过滤器（确保无法获取用户ID时不显示任何数据）
     */
    private void applyDefaultNoDataFilter(ProceedingJoinPoint point) {
        try {
            // 获取方法参数
            Object[] args = point.getArgs();
            
            // 查找需要过滤的参数（Map或QueryWrapper类型）
            for (Object arg : args) {
                if (arg instanceof Map) {
                    // 处理Map参数
                    Map<String, Object> paramMap = (Map<String, Object>) arg;
                    paramMap.put("customerIds", Arrays.asList(-1L)); // 添加不存在的客户ID
                } else if (arg instanceof QueryWrapper) {
                    // 处理QueryWrapper参数
                    QueryWrapper<?> queryWrapper = (QueryWrapper<?>) arg;
                    queryWrapper.in("customer_id", Arrays.asList(-1L)); // 添加不存在的客户ID
                } else if (arg != null) {
                    // 尝试处理PO对象
                    try {
                        Class<?> argClass = arg.getClass();
                        java.lang.reflect.Field customerIdsField = null;
                        
                        // 尝试获取customerIds字段
                        try {
                            customerIdsField = argClass.getDeclaredField("customerIds");
                        } catch (NoSuchFieldException e) {
                            // 如果当前类没有，尝试父类
                            customerIdsField = argClass.getSuperclass().getDeclaredField("customerIds");
                        }
                        
                        if (customerIdsField != null) {
                            customerIdsField.setAccessible(true);
                            customerIdsField.set(arg, Arrays.asList(-1L)); // 设置不存在的客户ID
                        }
                    } catch (Exception e) {
                        log.debug("无法为参数{}设置默认customerIds", arg.getClass().getName());
                    }
                }
            }
        } catch (Exception e) {
            log.error("应用默认无数据过滤器异常", e);
        }
    }
}